package com.gqzm.side.schedule;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.gqzm.side.common.component.RestRequest;
import com.gqzm.side.common.result.BizException;
import com.gqzm.side.common.result.ErrorCode;
import com.gqzm.side.common.socket.CloudPlatformSocketHandler;
import com.gqzm.side.common.utils.OshiUtils;
import com.gqzm.side.common.utils.PersistenceFileUtils;
import com.gqzm.side.domain.bo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName: {@link OshiSchedule}
 * @description:
 * @author: peter qin
 * @date: 2023 12 18
 * @version: 1.0
 **/
@Slf4j
@Component
public class OshiSchedule {

    @Value("${gqzm.detect-path:}")
    private String detectPath;

    @Value("${gqzm.detect-upload:}")
    private String uploadUrl;

    @Value("${gqzm.box-info-up:}")
    private String boxInfoUp;

    @Resource
    private RestRequest restRequest;

    private static final DateTimeFormatter format1
            = DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss-SSS");
    private static final DateTimeFormatter format2
            = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    //每10s上传一次
    @Scheduled(fixedDelay = 1000)
    @Async("gqzmTaskScheduler")
    public void monitorSchedule() {
        //持久化盒子编码信息获取
        PersistenceInfo pi = PersistenceFileUtils.readPersistence();
        //系统监控信息数据采集
        BoxMonitorMongodbBO monitor = BoxMonitorMongodbBO.builder()
                .code(pi.getCode())
                .name(pi.getName())
                .timestamp(System.currentTimeMillis())
                .cpu(OshiUtils.cpuInfo())
                .memory(OshiUtils.memInfo())
                .gpu(OshiUtils.gpuInfo())
                .net(OshiUtils.getNETWORK_INFO())
                .disks(OshiUtils.sysFileInfo())
                .system(BoxSystemInfo.builder()
                        .computerIp(SystemStaticInfo.getComputerIp())
                        .computerName(SystemStaticInfo.getComputerName())
                        .osArch(SystemStaticInfo.getOsArch())
                        .osName(SystemStaticInfo.getOsName())
                        .build())
                .build();
        double totalSpace = 0.0d;
        double usedSpace = 0.0d;
        for (BoxMonitorDisk bmd : monitor.getDisks()) {
            totalSpace += bmd.getTotal();
            usedSpace += bmd.getUsed();
        }

        try {
            restRequest.restCall(
                    HttpMethod.POST,
                    boxInfoUp,
                    JSON.parseObject(JSON.toJSONString(
                            BoxInfoSocketBO.builder()
                                    .monitor(monitor)
                                    .cameras(Lists.newArrayList())
                                    .code(pi.getCode())
                                    .name(pi.getName())
                                    .detectPath(detectPath)
                                    .ip(monitor.getSystem().getComputerIp())
                                    .status("1")
                                    .storageSpace(totalSpace)
                                    .storageUsed(usedSpace)
                                    .timestamp(LocalDateTime.now())
                                    .build()
                    )),
                    String.class
            );
        } catch (Exception e) {
            log.error("执行盒子信息上报异常", e);
        }
        //系统监控数据上报，调用rest接口
//        CloudPlatformSocketHandler.pushMessage(
//                BoxMessage.builder()
//                        .action("1")
//                        .code(pi.getCode())
//                        .timestamp(LocalDateTime.now())
//                        .data(JSON.toJSONString(
//                                BoxInfoSocketBO.builder()
//                                        .monitor(monitor)
//                                        .cameras(Lists.newArrayList())
//                                        .code(pi.getCode())
//                                        .name(pi.getName())
//                                        .detectPath(detectPath)
//                                        .ip(monitor.getSystem().getComputerIp())
//                                        .status("1")
//                                        .storageSpace(totalSpace)
//                                        .storageUsed(usedSpace)
//                                        .timestamp(LocalDateTime.now())
//                                        .build()
//                        ))
//                        .build()
//        );
    }


    @Scheduled(fixedDelay = 1000)
    @Async("gqzmTaskScheduler")
    public void networkSpeedCalculate() {
        OshiUtils.setNETWORK_INFO(OshiUtils.netInfo());
    }


    //20秒执行一次
    @Scheduled(fixedDelay = 20000)
    @Async("gqzmTaskScheduler")
    public void scanDetectPath() {
        PersistenceInfo pi = PersistenceFileUtils.readPersistence();
        Path path = Paths.get(detectPath);
        if (!Files.exists(path)) {
            return;
        }
        File[] fs = path.toFile().listFiles();
        if (Objects.isNull(fs)) {
            return;
        }
        List<File> l1 = new ArrayList<>();
        for (File f : fs) {
            if (f.isFile()) {
                l1.add(f);
            } else {
                File[] fs1 = f.listFiles();
                if (fs1 == null || fs1.length <= 0) {
                    continue;
                }
                l1.addAll(Arrays.asList(fs1));
            }
        }
        if (l1.isEmpty()) {
            return;
        }
        long timestamp = 0L;
        File current = new File(detectPath
                + File.separator
                + PersistenceFileUtils.readPersistence().getDetect());
        if (current.exists()) {
            timestamp = current.lastModified();
        }
        //读取基础目录下的图片
        long finalTimestamp = timestamp;
        List<File> list = l1.stream()
                .sorted(Comparator.comparingLong(File::lastModified))
                .filter(o -> o.lastModified() > finalTimestamp)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        String temp = null;
        for (File f : list) {
            //调用图片上传接口
            try {
                this.uploadDetect(f.getPath(), f.getName(), pi.getCode());
                temp = f.getName();
            } catch (Exception e) {
                log.error("执行检测结果:{} 上报失败，请检查", temp, e);
            }
        }
        if (StringUtils.isNotBlank(temp)) {
            //写入持久化读取进度
            pi.setDetect(temp);
            PersistenceFileUtils.writePersistence(pi);
        }
    }


    /**
     * 执行单个检测图片上传
     *
     * @param path
     * @param name
     */
    private void uploadDetect(String path, String name, String code) {
        if (StringUtils.isBlank(path)
                || StringUtils.isBlank(name)) {
            throw BizException.of(
                    ErrorCode.BASE_FAILED,
                    "检测结果文件路径或名称为空!"
            );
        }
        String[] split = StringUtils.substringBeforeLast(name, ".").split("_");
        if (split.length < 3) {
            log.info("检测图片:{} 命名无法解析，跳过", name);
            return;
        }
        //时间字符串，形如2023-12-19 10-10-10-101 -> 2023-12-19 10:10:10.101
        String timeStr = format2.format(LocalDateTime.from(format1.parse(split[0])));
        //检测类型名称
        String detectType = split[1];
        //检测置信度
        String score = split[2];
        //调用接口上传检测图片
        restRequest.uploadFile(
                code,
                path,
                uploadUrl,
                detectType,
                timeStr,
                Double.parseDouble(score)
        );
    }


}
